package com.campus.runrun.nettychat;

import com.alibaba.fastjson.JSON;
import com.campus.runrun.common.exception.CustomException;
import com.campus.runrun.common.exception.ResultCodeEnum;
import com.campus.runrun.common.utils.R;
import com.campus.runrun.common.utils.SpringContextUtils;
import com.campus.runrun.model.entity.ChatRecordEntity;
import com.campus.runrun.model.vo.ChatRecordSendVO;
import com.campus.runrun.model.vo.ChatRecordToClientVO;
import com.campus.runrun.service.api.ChatRecordService;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.concurrent.GlobalEventExecutor;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import java.text.SimpleDateFormat;
import static com.alibaba.fastjson.JSON.parseObject;

/**
 * 处理消息的handler
 * TextWebSocketFrame: 在netty中，是用于为websocket专门处理文本的对象，frame是消息的载体
 */
public class ChatHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    // 用来保存所有的客户端连接
    private static ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd hh:MM");

    // 当Channel中有新的事件消息会自动调用
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
        // 当接收到数据后会自动调用

        // 获取客户端发送过来的文本消息
        String text = msg.text();
        if (StringUtils.isEmpty(text)) {
            throw new CustomException(ResultCodeEnum.NULL_ERROR);
        }
        System.out.println("接收到消息数据为：" + text);

        NettyMessage nettyMessage = parseObject(text, NettyMessage.class);

        // 通过SpringUtil工具类获取Spring上下文容器
        ChatRecordService chatRecordService = SpringContextUtils.getBean(ChatRecordService.class);


        switch (nettyMessage.getType()) {
            // 处理客户端连接的消息
            case 0:
                // 建立用户与通道的关联
                Integer fromUserId = nettyMessage.getChatRecordSendVO().getFromUserId();
                String userKey = "userId:" + fromUserId;
                UserChannelMap.put(userKey, ctx.channel());
                System.out.println("建立用户:" + userKey + "与通道" + ctx.channel().id() + "的关联");
                UserChannelMap.print();
                Channel channel = UserChannelMap.get(userKey);
                channel.writeAndFlush(new TextWebSocketFrame("你好, 用户"+ fromUserId + "连接成功" ));
                break;
            // 处理客户端发送好友消息
            case 1:
                //System.out.println("接收到用户消息");
                // 将聊天消息保存到数据库
                ChatRecordSendVO chatRecordSendVO = nettyMessage.getChatRecordSendVO();
                // 不要给自己发信息
                if (chatRecordSendVO.getFromUserId().intValue() == chatRecordSendVO.getToUserId().intValue()) {
                    throw new CustomException(ResultCodeEnum.SEND_TO_SELF);
                }
                if (chatRecordSendVO == null) {
                    throw new CustomException(ResultCodeEnum.NULL_ERROR);
                }
                // 拿到带有自增id的chatRecord
                ChatRecordEntity chatRecord = chatRecordService.addOne(chatRecordSendVO);

                String oppositeKey = "userId:" + chatRecord.getToUserId();
                String myKey = "userId:" + chatRecord.getFromUserId();
                Channel oppositeChannel = UserChannelMap.get(oppositeKey);
                Channel myChannel = UserChannelMap.get(myKey);
                // 在线则直接发送
                if (oppositeChannel != null) {
                    ChatRecordToClientVO chatRecordToClientVO = new ChatRecordToClientVO();
                    BeanUtils.copyProperties(chatRecord, chatRecordToClientVO);
                    R result1 = R.ok().put("data", chatRecordToClientVO);
                    String result1Json = JSON.toJSONString(result1);
                    oppositeChannel.writeAndFlush(new TextWebSocketFrame(result1Json));
                }
                // 返回成功给发送方
                if (myChannel != null) {
                    R result2 = R.ok();
                    String result2Json = JSON.toJSONString(result2);
                    myChannel.writeAndFlush(new TextWebSocketFrame(result2Json));
                    break;
                }
            // 处理客户端的签收消息
            case 2:
                // 将消息记录设置为已读
                //chatRecordService.updateStatusHasRead(message.getChatRecord().getId());
                break;
            case 3:
                // 接收心跳消息
                //System.out.println("接收到心跳消息:" + JSON.toJSONString(nettyMessage));
                break;
        }

    }

    // 当有新的客户端连接服务器之后，会自动调用这个方法
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        // 将新的通道加入到clients
        clients.add(ctx.channel());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        UserChannelMap.removeByChannelId(ctx.channel().id().asLongText());
        ctx.channel().close();
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        System.out.println("关闭通道");
        UserChannelMap.removeByChannelId(ctx.channel().id().asLongText());
        UserChannelMap.print();
    }
}